/**
 * Container IOC容器 单例模式
 */
import { AsyncLocalStorage } from 'async_hooks'
import { EContainerServiceName, EServiceScope, IContainerService } from '@/types/container'

class Container {
  // 异步存储,用于存储请求周期内的服务实例，防止并发请求时服务实例被覆盖
  private asyncLocalStorage: AsyncLocalStorage<Map<EContainerServiceName, any>>

  private static instance: Container

  // 服务列表
  private services: { [key: string]: IContainerService } = {}

  private constructor() {
    this.asyncLocalStorage = new AsyncLocalStorage()
  }

  // 获取容器实例
  static getInstance(): Container {
    if (!Container.instance) {
      Container.instance = new Container()
    }
    return Container.instance
  }

  // 注入服务
  register<T>(name: EContainerServiceName, service: IContainerService<T>): void {
    // 默认单例模式
    this.services[name] = { scope: EServiceScope.SINGLETON, dependencies: [], ...service }
  }

  // 获取服务
  resolve<T>(name: EContainerServiceName): T {
    const service = this.services[name]

    // 服务不存在
    if (!service) {
      throw new Error(`Service ${name} not found`)
    }

    // 确保 constructor 和 instance 至少有一个被定义
    if (!service.constructor && !service.instance) {
      throw new Error(`Service ${name} must have either constructor or instance`)
    }

    const { scope = EServiceScope.SINGLETON } = service
    // 根据生命周期获取服务实例
    if (scope === EServiceScope.SINGLETON) {
      // 单例模式下 如果服务实例不存在 则创建
      if (!service.instance) {
        service.instance = this.createInstance<T>(service)
      }
      return service.instance
    } else if (scope === EServiceScope.REQUEST) {
      const store = this.asyncLocalStorage.getStore()
      let instance = store?.get(name)
      // 请求模式下 如果服务实例不存在 则创建
      if (!instance) {
        // 判断当前请求周期内的服务实例是否存在，不存在则创建
        instance = this.createInstance<T>(service)
        store?.set(name, instance)
      }
      return instance
    }

    throw new Error(`Unknown scope for service ${name}`)
  }

  // 创建服务实例
  private createInstance<T>(service: IContainerService<T>): T {
    if (service.instance) {
      // 存在传入的实例则直接返回服务实例
      return service.instance
    }
    // 否则则调用函数创建服务实例
    const { dependencies = [], constructor } = service
    if (constructor) {
      return new constructor(dependencies.map(dep => this.resolve(dep)))
    }
    throw new Error('Cannot create instance without constructor or instance')
  }

  // 中间件，用于初始化请求范围的存储
  middleware(callback: () => void): void {
    let store = this.asyncLocalStorage.getStore()
    if (!store) {
      store = new Map()
    }
    this.asyncLocalStorage.run(store, callback)
  }

  // 覆盖store
  overrideStoreValue(key: EContainerServiceName, value: any): void {
    let store = this.asyncLocalStorage.getStore()
    if (!store) {
      store = new Map<EContainerServiceName, any>()
    }
    store.set(key, value)
  }

  // 清空请求周期内的服务实例
  clearRequestScope(): void {
    this.asyncLocalStorage.getStore()?.clear()
  }
}

export default Container
